using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Xna.Framework;

namespace Oops.Xna.Framework.Physics
{
	/// <summary>
	/// Defines a collision shape in the form of a cube.
	/// </summary>
	public class CollisionBox : CollisionShape
	{
		#region BoxEdge Declaration
	    
		internal struct BoxEdge
		{
			internal BoxCornerType CornerType0;
			internal BoxCornerType CornerType1;
		}

		#endregion

		/// <summary>
		/// Gets an array of <see cref="CollisionBox.BoxEdges"/> instances.
		/// </summary>
		/// <remarks>
		/// Used with <see cref="CollisionBox.Corners" /> to simplify box edge retrieval during collision detection.
		/// </remarks>
		internal static BoxEdge[] Edges = new BoxEdge[12]
			{ 
				new BoxEdge() { CornerType0 = BoxCornerType.RightBottomBack, CornerType1 = BoxCornerType.RightTopBack },
				new BoxEdge() { CornerType0 = BoxCornerType.RightBottomBack, CornerType1 = BoxCornerType.LeftBottomBack },
				new BoxEdge() { CornerType0 = BoxCornerType.RightBottomBack, CornerType1 = BoxCornerType.RightBottomFront },
				new BoxEdge() { CornerType0 = BoxCornerType.LeftBottomBack, CornerType1 = BoxCornerType.LeftTopBack }, 
				new BoxEdge() { CornerType0 = BoxCornerType.LeftBottomBack, CornerType1 = BoxCornerType.LeftBottomFront },
				new BoxEdge() { CornerType0 = BoxCornerType.RightBottomFront, CornerType1 = BoxCornerType.RightTopFront },
				new BoxEdge() { CornerType0 = BoxCornerType.RightBottomFront, CornerType1 = BoxCornerType.LeftBottomFront },
				new BoxEdge() { CornerType0 = BoxCornerType.RightTopBack, CornerType1 = BoxCornerType.LeftTopBack },
				new BoxEdge() { CornerType0 = BoxCornerType.RightTopBack, CornerType1 = BoxCornerType.RightTopFront },
				new BoxEdge() { CornerType0 = BoxCornerType.LeftTopBack, CornerType1 = BoxCornerType.LeftTopFront },
				new BoxEdge() { CornerType0 = BoxCornerType.RightTopFront, CornerType1 = BoxCornerType.LeftTopFront },
				new BoxEdge() { CornerType0 = BoxCornerType.LeftBottomFront, CornerType1 = BoxCornerType.LeftTopFront }
			};

		/// <summary>
		/// Gets or set the extents of the <see cref="CollisionBox"/>.
		/// </summary>
		public Vector3 Extents;

		/// <summary>
		/// Gets the corner positions of the <see cref="CollisionBox"/>.
		/// </summary>
		/// <remarks>
		/// Do not set this field directly.  The corners of the <see cref="CollisionBox"/> get
		/// calculated when moved.
		/// </remarks>
		public Vector3[] Corners = new Vector3[8];

		/// <summary>
		/// Initializes a new instance of the <see cref="CollisionBox"/> class.
		/// </summary>
		public CollisionBox() : base(CollisionShapeType.Box) { }

		#region CollisionShape Members
		
		internal override void CalculateInternals()
		{
			// Call inherited method.
			base.CalculateInternals();
#if QUATERNION_ORIENTATION
			// Calculate the corner positions.
			Vector3 xAxis = QuaternionExtension.GetAxis(this.Orientation, QuaternionAxis.Right) * this.Extents.X;
			Vector3 yAxis = QuaternionExtension.GetAxis(this.Orientation, QuaternionAxis.Up) * this.Extents.Y;
			Vector3 zAxis = QuaternionExtension.GetAxis(this.Orientation, QuaternionAxis.Forward) * this.Extents.Z;

			Vector3 temp0 = this.Position + xAxis;
			Vector3 temp1 = this.Position - xAxis;
			Vector3 temp2 = yAxis + zAxis;
			Vector3 temp3 = yAxis - zAxis;

			this.Corners[(int)BoxCornerType.RightTopFront] = temp0 + temp2;
			this.Corners[(int)BoxCornerType.RightTopBack] = temp0 + temp3;
			this.Corners[(int)BoxCornerType.RightBottomFront] = temp0 - temp2;
			this.Corners[(int)BoxCornerType.RightBottomBack] = temp0 - temp3;
			this.Corners[(int)BoxCornerType.LeftTopFront] = temp1 + temp2;
			this.Corners[(int)BoxCornerType.LeftTopBack] = temp1 + temp3;
			this.Corners[(int)BoxCornerType.LeftBottomFront] = temp1 - temp2;
			this.Corners[(int)BoxCornerType.LeftBottomBack] = temp1 - temp3;
#else
#if INLINE
			// Calculate the corner positions.
			float x0 = this.Orientation.M11 * this.Extents.X;
			float y0 = this.Orientation.M12 * this.Extents.X;
			float z0 = this.Orientation.M13 * this.Extents.X;

			Vector3 temp0;
			temp0.X = this.Position.X + x0;
			temp0.Y = this.Position.Y + y0;
			temp0.Z = this.Position.Z + z0;

			Vector3 temp1;
			temp1.X = this.Position.X - x0;
			temp1.Y = this.Position.Y - y0;
			temp1.Z = this.Position.Z - z0;

			x0 = this.Orientation.M21 * this.Extents.Y;
			y0 = this.Orientation.M22 * this.Extents.Y;
			z0 = this.Orientation.M23 * this.Extents.Y;

			float x1 = this.Orientation.M31 * this.Extents.Z;
			float y1 = this.Orientation.M32 * this.Extents.Z;
			float z1 = this.Orientation.M33 * this.Extents.Z;

			Vector3 temp2;
			temp2.X = x0 + x1;
			temp2.Y = y0 + y1;
			temp2.Z = z0 + z1;

			Vector3 temp3;
			temp3.X = x0 - x1;
			temp3.Y = y0 - y1;
			temp3.Z = z0 - z1;

			this.Corners[(int)BoxCornerType.RightTopFront].X = temp0.X + temp2.X;
			this.Corners[(int)BoxCornerType.RightTopFront].Y = temp0.Y + temp2.Y;
			this.Corners[(int)BoxCornerType.RightTopFront].Z = temp0.Z + temp2.Z;

			this.Corners[(int)BoxCornerType.RightTopBack].X = temp0.X + temp3.X;
			this.Corners[(int)BoxCornerType.RightTopBack].Y = temp0.Y + temp3.Y;
			this.Corners[(int)BoxCornerType.RightTopBack].Z = temp0.Z + temp3.Z;

			this.Corners[(int)BoxCornerType.RightBottomFront].X = temp0.X - temp2.X;
			this.Corners[(int)BoxCornerType.RightBottomFront].Y = temp0.Y - temp2.Y;
			this.Corners[(int)BoxCornerType.RightBottomFront].Z = temp0.Z - temp2.Z;

			this.Corners[(int)BoxCornerType.RightBottomBack].X = temp0.X - temp3.X;
			this.Corners[(int)BoxCornerType.RightBottomBack].Y = temp0.Y - temp3.Y;
			this.Corners[(int)BoxCornerType.RightBottomBack].Z = temp0.Z - temp3.Z;

			this.Corners[(int)BoxCornerType.LeftTopFront].X = temp1.X + temp2.X;
			this.Corners[(int)BoxCornerType.LeftTopFront].Y = temp1.Y + temp2.Y;
			this.Corners[(int)BoxCornerType.LeftTopFront].Z = temp1.Z + temp2.Z;

			this.Corners[(int)BoxCornerType.LeftTopBack].X = temp1.X + temp3.X;
			this.Corners[(int)BoxCornerType.LeftTopBack].Y = temp1.Y + temp3.Y;
			this.Corners[(int)BoxCornerType.LeftTopBack].Z = temp1.Z + temp3.Z;

			this.Corners[(int)BoxCornerType.LeftBottomFront].X = temp1.X - temp2.X;
			this.Corners[(int)BoxCornerType.LeftBottomFront].Y = temp1.Y - temp2.Y;
			this.Corners[(int)BoxCornerType.LeftBottomFront].Z = temp1.Z - temp2.Z;

			this.Corners[(int)BoxCornerType.LeftBottomBack].X = temp1.X - temp3.X;
			this.Corners[(int)BoxCornerType.LeftBottomBack].Y = temp1.Y - temp3.Y;
			this.Corners[(int)BoxCornerType.LeftBottomBack].Z = temp1.Z - temp3.Z;
#elif REFERENCE
			// Calculate the corner positions.
			Vector3 xAxis;
			MatrixExtension.GetAxis(ref this.Orientation, MatrixAxis.X, out xAxis);
			Vector3.Multiply(ref xAxis, this.Extents.X, out xAxis);
			Vector3 yAxis;
			MatrixExtension.GetAxis(ref this.Orientation, MatrixAxis.Y, out yAxis);
			Vector3.Multiply(ref yAxis, this.Extents.Y, out yAxis);
			Vector3 zAxis;
			MatrixExtension.GetAxis(ref this.Orientation, MatrixAxis.Z, out zAxis);
			Vector3.Multiply(ref zAxis, this.Extents.Z, out zAxis);

			Vector3 temp0, temp1, temp2, temp3;
			Vector3.Add(ref this.Position, ref xAxis, out temp0);
			Vector3.Subtract(ref this.Position, ref xAxis, out temp1);
			Vector3.Add(ref yAxis, ref zAxis, out temp2);
			Vector3.Subtract(ref yAxis, ref zAxis, out temp3);

			Vector3.Add(ref temp0, ref temp2, out this.Corners[(int)BoxCornerType.RightTopFront]);
			Vector3.Add(ref temp0, ref temp3, out this.Corners[(int)BoxCornerType.RightTopBack]);
			Vector3.Subtract(ref temp0, ref temp2, out this.Corners[(int)BoxCornerType.RightBottomFront]);
			Vector3.Subtract(ref temp0, ref temp3, out this.Corners[(int)BoxCornerType.RightBottomBack]);
			Vector3.Add(ref temp1, ref temp2, out this.Corners[(int)BoxCornerType.LeftTopFront]);
			Vector3.Add(ref temp1, ref temp3, out this.Corners[(int)BoxCornerType.LeftTopBack]);
			Vector3.Subtract(ref temp1, ref temp2, out this.Corners[(int)BoxCornerType.LeftBottomFront]);
			Vector3.Subtract(ref temp1, ref temp3, out this.Corners[(int)BoxCornerType.LeftBottomBack]);
#else
			// Calculate the corner positions.
			Vector3 xAxis = MatrixExtension.GetAxis(this.Orientation, MatrixAxis.X) * this.Extents.X;
			Vector3 yAxis = MatrixExtension.GetAxis(this.Orientation, MatrixAxis.Y) * this.Extents.Y;
			Vector3 zAxis = MatrixExtension.GetAxis(this.Orientation, MatrixAxis.Z) * this.Extents.Z;

			Vector3 temp0 = this.Position + xAxis;
			Vector3 temp1 = this.Position - xAxis;
			Vector3 temp2 = yAxis + zAxis;
			Vector3 temp3 = yAxis - zAxis;

			this.Corners[(int)BoxCornerType.RightTopFront] = temp0 + temp2;
			this.Corners[(int)BoxCornerType.RightTopBack] = temp0 + temp3;
			this.Corners[(int)BoxCornerType.RightBottomFront] = temp0 - temp2;
			this.Corners[(int)BoxCornerType.RightBottomBack] = temp0 - temp3;
			this.Corners[(int)BoxCornerType.LeftTopFront] = temp1 + temp2;
			this.Corners[(int)BoxCornerType.LeftTopBack] = temp1 + temp3;
			this.Corners[(int)BoxCornerType.LeftBottomFront] = temp1 - temp2;
			this.Corners[(int)BoxCornerType.LeftBottomBack] = temp1 - temp3;
#endif
#endif
		}

		protected override void CalculateAABB()
		{
#if QUATERNION_ORIENTATION
			Matrix orientation = Matrix.CreateFromQuaternion(this.Orientation);

			// Calculate extents based on rotation.
			float x = Math.Abs(orientation.M11 * this.Extents.X) + Math.Abs(orientation.M21 * this.Extents.Y) + Math.Abs(orientation.M31 * this.Extents.Z);
			float y = Math.Abs(orientation.M12 * this.Extents.X) + Math.Abs(orientation.M22 * this.Extents.Y) + Math.Abs(orientation.M32 * this.Extents.Z);
			float z = Math.Abs(orientation.M13 * this.Extents.X) + Math.Abs(orientation.M23 * this.Extents.Y) + Math.Abs(orientation.M33 * this.Extents.Z);
#else
			// Calculate extents based on rotation.
			float x = Math.Abs(this.Orientation.M11 * this.Extents.X) + Math.Abs(this.Orientation.M21 * this.Extents.Y) + Math.Abs(this.Orientation.M31 * this.Extents.Z);
			float y = Math.Abs(this.Orientation.M12 * this.Extents.X) + Math.Abs(this.Orientation.M22 * this.Extents.Y) + Math.Abs(this.Orientation.M32 * this.Extents.Z);
			float z = Math.Abs(this.Orientation.M13 * this.Extents.X) + Math.Abs(this.Orientation.M23 * this.Extents.Y) + Math.Abs(this.Orientation.M33 * this.Extents.Z);
#endif
			// Update the axis-aligned bounding box for this shape.
			this.AABB.Min.X = this.Position.X - x;
			this.AABB.Max.X = this.Position.X + x;
			this.AABB.Min.Y = this.Position.Y - y;
			this.AABB.Max.Y = this.Position.Y + y;
			this.AABB.Min.Z = this.Position.Z - z;
			this.AABB.Max.Z = this.Position.Z + z;
		}

		public override bool IntersectsWith(ref CollisionRay ray, out Vector3 position, out Vector3 normal, out float t)
		{
			// Initialize return values.
			position = Vector3.Zero;
			normal = Vector3.Zero;
			t = float.MaxValue;

			// Initialize minimum and maximum values.
			float minimum = float.MinValue;
			float maximum = float.MaxValue;

			// Initialize the minimum and maximum axis.
			int minimumAxis = 0;
			int maximumAxis = 0;

			// Get the vector between the start of the ray and the box's position.
#if INLINE
#if XBOX
			Vector3 difference = Vector3.Zero;
#else
			Vector3 difference;
#endif
			difference.X = this.Position.X - ray.Position.X;
			difference.Y = this.Position.Y - ray.Position.Y;
			difference.Z = this.Position.Z - ray.Position.Z;
#elif REFERENCE
			Vector3 difference;
			Vector3.Subtract(ref this.Position, ref ray.Position, out difference);
#else
			Vector3 difference = this.Position - ray.Position;
#endif
			// Iterate on axes.
			Vector3 axis;
			for (int i = 0; i < 3; i++)
			{
				// Get the current box axis and extent.
#if QUATERNION_ORIENTATION
				axis = QuaternionExtension.GetAxis(ref this.Orientation, (QuaternionAxis)i);
#else
#if REFERENCE
				MatrixExtension.GetAxis(ref this.Orientation, (MatrixAxis)i, out axis);
#else
				axis = MatrixExtension.GetAxis(this.Orientation, (MatrixAxis)i);
#endif
#endif
				float extent = Vector3Extension.GetComponent(ref this.Extents, (VectorIndex)i);

				// Get the projection of the ray's vector and difference in positions along the axis.
#if INLINE
				float a = axis.X * ray.Vector.X + axis.Y * ray.Vector.Y + axis.Z * ray.Vector.Z;
				float b = axis.X * difference.X + axis.Y * difference.Y + axis.Z * difference.Z;
#elif REFERENCE
				float a = Vector3Extension.Dot(ref axis, ref ray.Vector);
				float b = Vector3Extension.Dot(ref axis, ref difference);
#else
				float a = Vector3.Dot(axis, ray.Vector);
				float b = Vector3.Dot(axis, difference);
#endif
				if (Math.Abs(a) < MathExtension.Epsilon)
				{
					if (-b - extent > 0.0f || -b + extent < 0.0f)
					{
						return false;
					}
				}
				else
				{
					// Get the projection amount along the collision ray for the current axis.
					float t0 = (b + extent) / a;
					float t1 = (b - extent) / a;

					// Swap projections if necessary.
					if (t0 > t1)
					{
						float tmp = t0;
						t0 = t1; 
						t1 = tmp;
					}

					// Hold onto the best minimum.
					if (t0 > minimum)
					{
						minimum = t0;
						minimumAxis = i;
					}

					// Hold onto the best maximum.
					if (t1 < maximum)
					{
						maximum = t1;
						maximumAxis = i;
					}

					// Validate range.
					if (minimum > maximum)
					{
						return false;
					}

					// Validate the maximum value.
					if (maximum < 0.0f)
					{
						return false;
					}
				}
			}

			// Determine the winning axis.
			int bestAxis;
			if (minimum > 0.0f)
			{
				bestAxis = minimumAxis;
				t = minimum;
			}
			else
			{
				bestAxis = maximumAxis;
				t = maximum;
			}

			// Keep within valid range.
			t = MathHelper.Clamp(t, 0.0f, 1.0f);

			// Get the position and normal of the intersection.
#if QUATERNION_ORIENTATION
			position = ray.GetPointAt(t);
			normal = QuaternionExtension.GetAxis(this.Orientation, (QuaternionAxis)bestAxis);
#else
#if REFERENCE
			ray.GetPointAt(t, out position);
			MatrixExtension.GetAxis(ref this.Orientation, (MatrixAxis)bestAxis, out normal);
#else
			position = ray.GetPointAt(t);
			normal = MatrixExtension.GetAxis(this.Orientation, (MatrixAxis)bestAxis);
#endif
#endif
			// Make sure the normal is pointing in the correct direction.
			if (Vector3Extension.Dot(ref normal, ref ray.Vector) > 0.0f)
			{
#if INLINE
				normal.X = -normal.X;
				normal.Y = -normal.Y;
				normal.Z = -normal.Z;
#elif REFERENCE
				Vector3.Negate(ref normal, out normal);
#else
				normal = -normal;
#endif
			}

			// An intersection occurred.
			return true;
		}

		protected internal override float GetVolume()
		{
			return (this.Extents.X * this.Extents.Y * this.Extents.Z) * 8.0f;
		}

		public override void CalculateMassProperties(float density, out float mass, out Matrix inertiaTensor)
		{
			// Get the mass.
			mass = density * this.GetVolume();

			// Calculate some values used below.
			float massFactor = (1.0f / 12.0f) * mass;
			float widthSquared = this.Extents.X * this.Extents.X * 4.0f;
			float heightSquared = this.Extents.Y * this.Extents.Y * 4.0f;
			float depthSquared = this.Extents.Z * this.Extents.Z * 4.0f;

			// Get the inertia tensor.
#if XBOX
			inertiaTensor = MatrixExtension.Zero;
#endif
			inertiaTensor.M11 = massFactor * (heightSquared + depthSquared);
			inertiaTensor.M12 = 0.0f;
			inertiaTensor.M13 = 0.0f;
			inertiaTensor.M14 = 0.0f;

			inertiaTensor.M21 = 0.0f;
			inertiaTensor.M22 = massFactor * (widthSquared + depthSquared);
			inertiaTensor.M23 = 0.0f;
			inertiaTensor.M24 = 0.0f;

			inertiaTensor.M31 = 0.0f;
			inertiaTensor.M32 = 0.0f;
			inertiaTensor.M33 = massFactor * (widthSquared + heightSquared);
			inertiaTensor.M34 = 0.0f;

			inertiaTensor.M41 = 0.0f;
			inertiaTensor.M42 = 0.0f;
			inertiaTensor.M43 = 0.0f;
			inertiaTensor.M44 = 1.0f;
						
			// Adjust the inertia tensor by the offset.
			inertiaTensor = MatrixExtension.TransferAxis(inertiaTensor, this.OffsetPosition, mass);
		}

		#endregion
#if QUATERNION_ORIENTATION
		internal static void GetBoxCorners(ref Vector3 position, ref Quaternion orientation, ref Vector3 extents, Vector3[] corners)
		{
			// Calculate the corner positions.
			Vector3 xAxis = QuaternionExtension.GetAxis(ref orientation, QuaternionAxis.Right) * extents.X;
			Vector3 yAxis = QuaternionExtension.GetAxis(ref orientation, QuaternionAxis.Up) * extents.Y;
			Vector3 zAxis = QuaternionExtension.GetAxis(ref orientation, QuaternionAxis.Forward) * extents.Z;

			Vector3 temp0 = position + xAxis;
			Vector3 temp1 = position - xAxis;
			Vector3 temp2 = yAxis + zAxis;
			Vector3 temp3 = yAxis - zAxis;

			corners[(int)BoxCornerType.RightTopFront] = temp0 + temp2;
			corners[(int)BoxCornerType.RightTopBack] = temp0 + temp3;
			corners[(int)BoxCornerType.RightBottomFront] = temp0 - temp2;
			corners[(int)BoxCornerType.RightBottomBack] = temp0 - temp3;
			corners[(int)BoxCornerType.LeftTopFront] = temp1 + temp2;
			corners[(int)BoxCornerType.LeftTopBack] = temp1 + temp3;
			corners[(int)BoxCornerType.LeftBottomFront] = temp1 - temp2;
			corners[(int)BoxCornerType.LeftBottomBack] = temp1 - temp3;
		}
#else
		internal static void GetBoxCorners(ref Vector3 position, ref Matrix orientation, ref Vector3 extents, Vector3[] corners)
		{
#if INLINE
			// Calculate the corner positions.
			float x0 = orientation.M11 * extents.X;
			float y0 = orientation.M12 * extents.X;
			float z0 = orientation.M13 * extents.X;

			Vector3 temp0;
			temp0.X = position.X + x0;
			temp0.Y = position.Y + y0;
			temp0.Z = position.Z + z0;

			Vector3 temp1;
			temp1.X = position.X - x0;
			temp1.Y = position.Y - y0;
			temp1.Z = position.Z - z0;

			x0 = orientation.M21 * extents.Y;
			y0 = orientation.M22 * extents.Y;
			z0 = orientation.M23 * extents.Y;

			float x1 = orientation.M31 * extents.Z;
			float y1 = orientation.M32 * extents.Z;
			float z1 = orientation.M33 * extents.Z;

			Vector3 temp2;
			temp2.X = x0 + x1;
			temp2.Y = y0 + y1;
			temp2.Z = z0 + z1;

			Vector3 temp3;
			temp3.X = x0 - x1;
			temp3.Y = y0 - y1;
			temp3.Z = z0 - z1;

			corners[(int)BoxCornerType.RightTopFront].X = temp0.X + temp2.X;
			corners[(int)BoxCornerType.RightTopFront].Y = temp0.Y + temp2.Y;
			corners[(int)BoxCornerType.RightTopFront].Z = temp0.Z + temp2.Z;

			corners[(int)BoxCornerType.RightTopBack].X = temp0.X + temp3.X;
			corners[(int)BoxCornerType.RightTopBack].Y = temp0.Y + temp3.Y;
			corners[(int)BoxCornerType.RightTopBack].Z = temp0.Z + temp3.Z;

			corners[(int)BoxCornerType.RightBottomFront].X = temp0.X - temp2.X;
			corners[(int)BoxCornerType.RightBottomFront].Y = temp0.Y - temp2.Y;
			corners[(int)BoxCornerType.RightBottomFront].Z = temp0.Z - temp2.Z;

			corners[(int)BoxCornerType.RightBottomBack].X = temp0.X - temp3.X;
			corners[(int)BoxCornerType.RightBottomBack].Y = temp0.Y - temp3.Y;
			corners[(int)BoxCornerType.RightBottomBack].Z = temp0.Z - temp3.Z;

			corners[(int)BoxCornerType.LeftTopFront].X = temp1.X + temp2.X;
			corners[(int)BoxCornerType.LeftTopFront].Y = temp1.Y + temp2.Y;
			corners[(int)BoxCornerType.LeftTopFront].Z = temp1.Z + temp2.Z;

			corners[(int)BoxCornerType.LeftTopBack].X = temp1.X + temp3.X;
			corners[(int)BoxCornerType.LeftTopBack].Y = temp1.Y + temp3.Y;
			corners[(int)BoxCornerType.LeftTopBack].Z = temp1.Z + temp3.Z;

			corners[(int)BoxCornerType.LeftBottomFront].X = temp1.X - temp2.X;
			corners[(int)BoxCornerType.LeftBottomFront].Y = temp1.Y - temp2.Y;
			corners[(int)BoxCornerType.LeftBottomFront].Z = temp1.Z - temp2.Z;

			corners[(int)BoxCornerType.LeftBottomBack].X = temp1.X - temp3.X;
			corners[(int)BoxCornerType.LeftBottomBack].Y = temp1.Y - temp3.Y;
			corners[(int)BoxCornerType.LeftBottomBack].Z = temp1.Z - temp3.Z;
#elif REFERENCE
			// Calculate the corner positions.
			Vector3 xAxis;
			MatrixExtension.GetAxis(ref orientation, MatrixAxis.X, out xAxis);
			Vector3.Multiply(ref xAxis, extents.X, out xAxis);
			Vector3 yAxis;
			MatrixExtension.GetAxis(ref orientation, MatrixAxis.Y, out yAxis);
			Vector3.Multiply(ref yAxis, extents.Y, out yAxis);
			Vector3 zAxis;
			MatrixExtension.GetAxis(ref orientation, MatrixAxis.Z, out zAxis);
			Vector3.Multiply(ref zAxis, extents.Z, out zAxis);

			Vector3 temp0, temp1, temp2, temp3;
			Vector3.Add(ref position, ref xAxis, out temp0);
			Vector3.Subtract(ref position, ref xAxis, out temp1);
			Vector3.Add(ref yAxis, ref zAxis, out temp2);
			Vector3.Subtract(ref yAxis, ref zAxis, out temp3);

			Vector3.Add(ref temp0, ref temp2, out corners[(int)BoxCornerType.RightTopFront]);
			Vector3.Add(ref temp0, ref temp3, out corners[(int)BoxCornerType.RightTopBack]);
			Vector3.Subtract(ref temp0, ref temp2, out corners[(int)BoxCornerType.RightBottomFront]);
			Vector3.Subtract(ref temp0, ref temp3, out corners[(int)BoxCornerType.RightBottomBack]);
			Vector3.Add(ref temp1, ref temp2, out corners[(int)BoxCornerType.LeftTopFront]);
			Vector3.Add(ref temp1, ref temp3, out corners[(int)BoxCornerType.LeftTopBack]);
			Vector3.Subtract(ref temp1, ref temp2, out corners[(int)BoxCornerType.LeftBottomFront]);
			Vector3.Subtract(ref temp1, ref temp3, out corners[(int)BoxCornerType.LeftBottomBack]);
#else
			// Calculate the corner positions.
			Vector3 xAxis = MatrixExtension.GetAxis(orientation, MatrixAxis.X) * extents.X;
			Vector3 yAxis = MatrixExtension.GetAxis(orientation, MatrixAxis.Y) * extents.Y;
			Vector3 zAxis = MatrixExtension.GetAxis(orientation, MatrixAxis.Z) * extents.Z;

			Vector3 temp0 = position + xAxis;
			Vector3 temp1 = position - xAxis;
			Vector3 temp2 = yAxis + zAxis;
			Vector3 temp3 = yAxis - zAxis;

			corners[(int)BoxCornerType.RightTopFront] = temp0 + temp2;
			corners[(int)BoxCornerType.RightTopBack] = temp0 + temp3;
			corners[(int)BoxCornerType.RightBottomFront] = temp0 - temp2;
			corners[(int)BoxCornerType.RightBottomBack] = temp0 - temp3;
			corners[(int)BoxCornerType.LeftTopFront] = temp1 + temp2;
			corners[(int)BoxCornerType.LeftTopBack] = temp1 + temp3;
			corners[(int)BoxCornerType.LeftBottomFront] = temp1 - temp2;
			corners[(int)BoxCornerType.LeftBottomBack] = temp1 - temp3;
#endif
		}
#endif
	}
}
